package com.clp.protocol.core.pdu.nbytepdu.time2a;

import com.clp.protocol.core.pdu.nbytepdu.BaseNBytePduClip;
import com.clp.protocol.core.pdu.ByteToStringFormat;
import com.clp.protocol.core.utils.ByteUtil;
import io.netty.buffer.ByteBuf;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;

import java.util.Calendar;
import java.util.Date;
import java.util.Objects;
import java.util.function.Consumer;

@Getter
@NoArgsConstructor
@AllArgsConstructor
public class CP56Time2a extends Time2a {
    public static int bytesLen = 7;
    /**
     * 年
     */
    private int year;
    /**
     * 月
     */
    private int month;
    /**
     * 星期
     */
    private Week week;
    /**
     * 日
     */
    private int day;
    /**
     * 小时
     */
    private int hour;
    /**
     * 分钟
     */
    private int minute;
    /**
     * 秒
     */
    private int second;
    /**
     * 毫秒
     */
    private int millisecond;

    @Override
    public CP56Time2a refreshFrom(ByteBuf buf) {
        byte[] bytes = new byte[7];
        buf.readBytes(bytes);
        this.year = (bytes[6] & 0x7F) + 2000;
        this.month = bytes[5] & 0x0F;
        this.week = Week.gain((bytes[4] >> 5) & 0x07);
        this.day = bytes[4] & 0x1F;
        this.hour = bytes[3] & 0x1F;
        this.minute = bytes[2] & 0x3F;
        int allMs = ((bytes[1] & 0xFF) << 8) + (bytes[0] & 0xFF);
        this.second = allMs / 1000;
        this.millisecond = allMs % 1000;
        return this;
    }

    @Override
    public boolean isValid() {
        if (year < 0) return false;
        if (month <= 0 || month > 12) return false;
        if (week == null) return false;
        if (day <= 0 || day > 31) return false; // TODO 这里需要根据年月判断，暂时简化
        if (hour < 0 || hour >= 24) return false;
        if (minute < 0 || minute >= 60) return false;
        if (second < 0 || second >= 60) return false;
        return millisecond >= 0 && millisecond < 1000;
    }

    @Override
    public void writeBytesTo(ByteBuf buf) {
        // 计算总毫秒数
        int allMs = second * 1000 + millisecond;
        // 写入
        buf.writeShortLE(allMs);
        buf.writeByte(minute & 0x3F);
        buf.writeByte(hour & 0x1F);
        byte wdByte = 0x00;
        wdByte |= week.getVal() & 0x07; wdByte <<= 5;
        wdByte |= day & 0x1F;
        buf.writeByte(wdByte);
        buf.writeByte(month & 0x0F);
        buf.writeByte((year - 2000) & 0x7F);
    }

    @Override
    public void writeFormattedByteStringsTo(StringBuilder sb, String frameClipBytesSeparator, String byteSeparator, ByteToStringFormat byteFormat) {
        // 计算总毫秒数
        int allMs = second * 1000 + millisecond;
        byte[] msBytes = ByteUtil.intToBytes2LE(allMs);
        sb.append(byteFormat.format(msBytes[0]));
        for (int i = 1; i < msBytes.length; i++) {
            sb.append(byteSeparator).append(byteFormat.format(msBytes[i]));
        }
        sb.append(byteSeparator).append(byteFormat.format((byte) (minute & 0x3F)));
        sb.append(byteSeparator).append(byteFormat.format((byte) (hour & 0x1F)));
        byte wdByte = 0x00;
        wdByte |= week.getVal() & 0x07; wdByte <<= 5;
        wdByte |= day & 0x1F;
        sb.append(byteSeparator).append(byteFormat.format(wdByte));
        sb.append(byteSeparator).append(byteFormat.format((byte) (month & 0x0F)));
        sb.append(byteSeparator).append(byteFormat.format((byte) ((year - 2000) & 0x7F)));
    }

    @Override
    public void writeSimpleDescriptionTo(StringBuilder sb) {
        sb.append("CP56Time2a<").append(year).append("year").append(month).append("month").append(day).append("day(")
                .append(week.getVal()).append(") ").append(hour).append(":").append(minute).append(":")
                .append(second).append(":").append(millisecond).append(">");
    }

    @Override
    public void writeDetailDescriptionTo(StringBuilder sb) {
        sb.append("CP56Time2a<").append(year).append("年").append(month).append("月").append(day).append("日(")
                .append(week.getDesc()).append(") ").append(hour).append(":").append(minute).append(":")
                .append(second).append(":").append(millisecond).append(">");
    }

    @Override
    protected void forEachOneLevelChild(Consumer<BaseNBytePduClip<?>> consumer) {
    }

    @Override
    public Date toDate() {
        Calendar calendar = Calendar.getInstance();
        calendar.set(Calendar.YEAR, year);
        calendar.set(Calendar.MONTH, month - 1);
        calendar.set(Calendar.DAY_OF_MONTH, day);
        calendar.set(Calendar.HOUR_OF_DAY, hour);
        calendar.set(Calendar.MINUTE, minute);
        calendar.set(Calendar.SECOND, second);
        calendar.set(Calendar.MILLISECOND, millisecond);
        return calendar.getTime();
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        CP56Time2a that = (CP56Time2a) o;
        return year == that.year && month == that.month && day == that.day && hour == that.hour && minute == that.minute && second == that.second && millisecond == that.millisecond && week == that.week;
    }

    @Override
    public int hashCode() {
        return Objects.hash(year, month, week, day, hour, minute, second, millisecond);
    }
}
